{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# ignore_box2_or_not"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "def find_inner_box_isin_outer_box(box1: list, box2: list, scale: int = 5) -> bool:\n",
    "    \"\"\"determine whether a box is in another box\n",
    "\n",
    "    Args:\n",
    "        outer_box (list): 假设外部盒子 [x_min, y_min, x_max, y_max]\n",
    "        inner_box (list): 假设内部盒子 [x_min, y_min, x_max, y_max]\n",
    "        scale (int):      调整盒子的大小,相当于忽略宽高输出scale的大小. Defaults to 5.\n",
    "\n",
    "    Returns:\n",
    "        bool: 外部盒子是否包含内部盒子\n",
    "    \"\"\"\n",
    "    # 外面包裹内部\n",
    "    left   = int(box1[0] / scale) - int(box2[0] / scale) # < 0 说明outer_box更靠左\n",
    "    top    = int(box1[1] / scale) - int(box2[1] / scale) # < 0 说明outer_box更靠上\n",
    "    right  = int(box1[2] / scale) - int(box2[2] / scale) # > 0 说明outer_box更靠右\n",
    "    bottom = int(box1[3] / scale) - int(box2[3] / scale) # > 0 说明outer_box更靠下\n",
    "\n",
    "    if left <= 0 and top <= 0 and right >= 0 and bottom >= 0:\n",
    "        return True\n",
    "    else:\n",
    "        return False"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "True\n",
      "False\n",
      "False\n",
      "False\n",
      "True\n",
      "False\n",
      "False\n"
     ]
    }
   ],
   "source": [
    "# box1, box2\n",
    "boxes = [\n",
    "    [[50, 50, 100, 100], [60, 60, 90, 90]],\n",
    "    [[50, 50, 100, 100], [110, 110, 120, 120]],\n",
    "    [[50, 50, 100, 100], [10, 10, 20, 20]],\n",
    "    [[50, 50, 100, 100], [95, 95, 105, 105]],\n",
    "    [[50, 50, 100, 100], [95, 95, 102, 102]],\n",
    "    [[50, 50, 100, 100], [45, 45, 55, 55]],\n",
    "    [[50, 50, 100, 100], [48, 48, 55, 55]],\n",
    "]\n",
    "\n",
    "for box1, box2 in boxes:\n",
    "    print(find_inner_box_isin_outer_box(box1, box2))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "def ignore_box2_or_not(box1: list, box2: list, ratio: float = 0.75) -> bool:\n",
    "    \"\"\"determine whether a box is in another box\n",
    "\n",
    "    Args:\n",
    "        box1 (list): 假设外部盒子 [x_min, y_min, x_max, y_max]\n",
    "        box2 (list): 假设内部盒子 [x_min, y_min, x_max, y_max]\n",
    "        ratio (float): inner_box相当于box2的面积的阈值,大于阈值就忽略. Defaults to 0.75.\n",
    "\n",
    "    Returns:\n",
    "        bool: 外部盒子是否包含内部盒子\n",
    "    \"\"\"\n",
    "    # 内部盒子面积\n",
    "    print(max(box1[0], box2[0]))\n",
    "    inner_box_x1 = max(box1[0], box2[0])\n",
    "    inner_box_y1 = max(box1[1], box2[1])\n",
    "    inner_box_x2 = min(box1[2], box2[2])\n",
    "    inner_box_y2 = min(box1[3], box2[3])\n",
    "    # max 用来判断是否重叠\n",
    "    inner_box_area = max(inner_box_x2 - inner_box_x1, 0) * max(inner_box_y2 - inner_box_y1, 0)\n",
    "\n",
    "    box2_area = (box2[2] - box2[0]) * (box2[3] - box2[1])\n",
    "    print(inner_box_area / box2_area)\n",
    "    if inner_box_area / box2_area > ratio:\n",
    "        return True\n",
    "    else:\n",
    "        return False"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "60\n",
      "1.0\n",
      "True\n",
      "110\n",
      "0.0\n",
      "False\n",
      "50\n",
      "0.0\n",
      "False\n",
      "95\n",
      "0.25\n",
      "False\n",
      "95\n",
      "0.5102040816326531\n",
      "False\n",
      "50\n",
      "0.25\n",
      "False\n",
      "50\n",
      "0.5102040816326531\n",
      "False\n"
     ]
    }
   ],
   "source": [
    "# box1, box2\n",
    "boxes = [\n",
    "    [[50, 50, 100, 100], [60, 60, 90, 90]],\n",
    "    [[50, 50, 100, 100], [110, 110, 120, 120]],\n",
    "    [[50, 50, 100, 100], [10, 10, 20, 20]],\n",
    "    [[50, 50, 100, 100], [95, 95, 105, 105]],\n",
    "    [[50, 50, 100, 100], [95, 95, 102, 102]],\n",
    "    [[50, 50, 100, 100], [45, 45, 55, 55]],\n",
    "    [[50, 50, 100, 100], [48, 48, 55, 55]],\n",
    "]\n",
    "\n",
    "for box1, box2 in boxes:\n",
    "    print(ignore_box2_or_not(box1, box2))"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# ignore_boxes"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "detections = np.array([[ 10, 0.8, 200.04971, 196.26697, 489.98325, 424.07892],\n",
    "                        [10, 0.7, 141.04881, 311.3442 , 228.94856, 408.5379 ],\n",
    "                        [10, 0.6, 0.       , 303.4387 , 175.52124, 424.90558],\n",
    "                        [10, 0.5, 176.42613, 0.       , 460.68604, 227.06232],\n",
    "                        [10, 0.3, 384.6766 , 283.063  , 419.97977, 335.35898],\n",
    "                        [10, 0.8, 97.71875 , 346.97867, 103.96518, 353.037  ],\n",
    "                        [10, 0.7, 575.25476, 195.62448, 628.17926, 291.2721 ],\n",
    "                        [11, 0.6, 450.49182, 1.8310547, 640.     , 292.99066],\n",
    "                        [11, 0.7, 73.79396 , 368.1626 , 79.10231 , 372.40448],\n",
    "                        [10, 0.9, 84.013214, 332.34296, 89.18914 , 337.10605],\n",
    "                        [12, 0.8, 596.2429 , 248.21837, 601.9428 , 253.99461],\n",
    "                        [10, 0.1, 372.0439 , 363.4396 , 378.0838 , 368.31393]])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([10., 11., 12.])"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 获取每个类别\n",
    "classes = np.unique(detections[:, 0])\n",
    "classes"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "new_detections = []\n",
    "\n",
    "# 获取每个类别\n",
    "classes = np.unique(detections[:, 0])\n",
    "# 遍历单一类别\n",
    "for cls in classes:\n",
    "    dets_sig_cls = detections[detections[:, 0] == cls]\n",
    "    # 如果一个类别只有1个框,就直接保存\n",
    "    if len(dets_sig_cls) == 1:\n",
    "        new_detections.append(dets_sig_cls)\n",
    "        continue\n",
    "    # 求面积,根据面积排序,不是最好的办法\n",
    "    h = dets_sig_cls[:, 5] - dets_sig_cls[:, 3]\n",
    "    w = dets_sig_cls[:, 4] - dets_sig_cls[:, 2]\n",
    "    area = np.array(h * w)\n",
    "    index = area.argsort()              # 得到面积排序index\n",
    "    index = index[::-1]                 # 转换为降序\n",
    "\n",
    "    # max_i代表大的框index,min_i代表小的框index,所以不是顺序的,会出现类似 [3,0,1,4,2]的顺序,保存时也保存对应的位置上,对应原数据\n",
    "    keeps = []\n",
    "    for i, max_i in enumerate(index[:-1]):\n",
    "        # 默认都不包含\n",
    "        keep = [False] * len(dets_sig_cls)\n",
    "        for min_i in index[i+1:]:\n",
    "            isin = ignore_box2_or_not(dets_sig_cls[max_i, 2:], dets_sig_cls[min_i, 2:])\n",
    "            keep[min_i] = isin\n",
    "        keeps.append(keep)\n",
    "    # 取反,原本False为不包含,True为包含,取反后False为不保留,True为保留\n",
    "    keeps = ~np.array(keeps)\n",
    "    # print(keeps)\n",
    "    # 每一行代表被判断的框相对于判断框是否要保留\n",
    "    # 每一列代表对应index的框是否保留\n",
    "    # [[True, True, True, True, False, True,  True,  True, True,  True,  True,  False],\n",
    "    #  [True, True, True, True, True,  True,  True,  True, True,  True,  True,  True],\n",
    "    #  [True, True, True, True, True,  True,  False, True, True,  True,  False, True],\n",
    "    #  [True, True, True, True, True,  False, True,  True, False, False, True,  True],\n",
    "    #  [True, True, True, True, True,  True,  True,  True, True,  True,  True,  True],\n",
    "    #  [True, True, True, True, True,  True,  True,  True, True,  True,  False, True],\n",
    "    #  [True, True, True, True, True,  True,  True,  True, True,  True,  True,  True],\n",
    "    #  [True, True, True, True, True,  True,  True,  True, True,  True,  True,  True],\n",
    "    #  [True, True, True, True, True,  True,  True,  True, True,  True,  True,  True],\n",
    "    #  [True, True, True, True, True,  True,  True,  True, True,  True,  True,  True],\n",
    "    #  [True, True, True, True, True,  True,  True,  True, True,  True,  True,  True]]\n",
    "\n",
    "    # 最终保留的index,True/False\n",
    "    # keeps.T: 转置之后每行代表是否要保留这个框\n",
    "    final_keep = np.all(keeps.T, axis=-1)\n",
    "    new_detections.append(dets_sig_cls[final_keep])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "3"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "len(new_detections)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[1.0000000e+01, 8.0000000e-01, 2.0004971e+02, 1.9626697e+02,\n",
       "        4.8998325e+02, 4.2407892e+02],\n",
       "       [1.0000000e+01, 7.0000000e-01, 1.4104881e+02, 3.1134420e+02,\n",
       "        2.2894856e+02, 4.0853790e+02],\n",
       "       [1.0000000e+01, 6.0000000e-01, 0.0000000e+00, 3.0343870e+02,\n",
       "        1.7552124e+02, 4.2490558e+02],\n",
       "       [1.0000000e+01, 5.0000000e-01, 1.7642613e+02, 0.0000000e+00,\n",
       "        4.6068604e+02, 2.2706232e+02],\n",
       "       [1.0000000e+01, 7.0000000e-01, 5.7525476e+02, 1.9562448e+02,\n",
       "        6.2817926e+02, 2.9127210e+02],\n",
       "       [1.1000000e+01, 6.0000000e-01, 4.5049182e+02, 1.8310547e+00,\n",
       "        6.4000000e+02, 2.9299066e+02],\n",
       "       [1.1000000e+01, 7.0000000e-01, 7.3793960e+01, 3.6816260e+02,\n",
       "        7.9102310e+01, 3.7240448e+02],\n",
       "       [1.2000000e+01, 8.0000000e-01, 5.9624290e+02, 2.4821837e+02,\n",
       "        6.0194280e+02, 2.5399461e+02]])"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "new_detections1 = np.concatenate(new_detections, axis=0)\n",
    "new_detections1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([6.60503251e+04, 8.54330193e+03, 2.13200174e+04, 6.45447146e+04,\n",
       "       5.06210246e+03, 5.51771269e+04, 2.25173837e+01, 3.29239904e+01])"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "h = new_detections1[:, 5] - new_detections1[:, 3]\n",
    "w = new_detections1[:, 4] - new_detections1[:, 2]\n",
    "h * w"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "pytorch",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.9"
  },
  "orig_nbformat": 4
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
